<?php

Yii::import('application.vendors.oauth-php.OAuthStore');
Yii::import('application.vendors.oauth-php.OAuthRequester');
abstract class SocialProvider extends CComponent
{
    /**
     * @var string the ID of the {@link CDbConnection} application component.
     */
    public $connectionID='db';
    /**
     * @var string name of the DB table to store cache content. Defaults to 'user_connection'.
     * Note, if {@link autoCreateSocialProviderTable} is false and you want to create the DB table
     * manually by yourself, you need to make sure the DB table is of the following structure:
     * <pre>
     * (id INTEGER(11) PRIMARY KEY, user_id INTEGER(11), type TINYINT(1), identify VARCHAR(100))
     * </pre>
     * @see autoCreateSocialProviderTable
     */
    public $SocialProviderTableName='user_connect';
    /**
     * @var boolean whether the cache DB table should be created automatically if it does not exist. Defaults to true.
     * If you already have the table created, it is recommended you set this property to be false to improve performance.
     * @see SocialProviderTableName
     */
    public $autoCreateSocialProviderTable=false;
    
    public $type;
    public $identify;
    
    /**
    * social connect infomation
    * example:
    * array(
            'consumer_key' => 'cungmuasam.net',
            'consumer_secret' => 'zndEK5rgwA1C1ASqs2mMshGr',
            'server_uri' => 'https://spreadsheets.google.com',
            'signature_methods' => array('HMAC-SHA1', 'PLAINTEXT'),
            'request_token_uri' => 'https://www.google.com/accounts/OAuthGetRequestToken',
            'authorize_uri' => 'https://www.google.com/accounts/OAuthAuthorizeToken',
            'access_token_uri' => 'https://www.google.com/accounts/OAuthGetAccessToken',
        );
    * 
    * @var array
    */
    public $server = array();
    /**
    * extra arguments for when requesting the request token
    * 
    * @var array
    * default
    *   array(
    *       'oauth_callback'=><current route>,
    *       'scope'=>'',
    *   );
    */
    public $requestTokenParams = array();

    /**
     * @var CDbConnection the DB connection instance
     */
    private $_db;
    
    public function init()
    {
        $db=$this->getDbConnection();
        $db->setActive(true);
        if($this->autoCreateSocialProviderTable)
        {
            $sql="SELECT id FROM {$this->SocialProviderTableName} LIMIT 1";
            try
            {
                $db->createCommand($sql)->execute();
            }
            catch(Exception $e)
            {
                $this->createSocialProviderTable($db,$this->SocialProviderTableName);
            }
        }
    }

    /**
     * Creates the cache DB table.
     * @param CDbConnection $db the database connection
     * @param string $tableName the name of the table to be created
     */
    protected function createSocialProviderTable($db,$tableName)
    {
        $sql=<<<EOD
CREATE TABLE $tableName (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT '0',
  `type` varchar(20) DEFAULT '',
  `identify` varchar(100) DEFAULT '',
  PRIMARY KEY (`id`)
)
EOD;
        $db->createCommand($sql)->execute();
    }

    /**
     * @return CDbConnection the DB connection instance
     * @throws CException if {@link connectionID} does not point to a valid application component.
     */
    public function getDbConnection()
    {
        if($this->_db!==null)
            return $this->_db;
        else
        {
            $id=$this->connectionID;
            if(($this->_db=Yii::app()->getComponent($id)) instanceof CDbConnection)
                return $this->_db;
            else
                throw new CException(Yii::t('SocialProvider','SocialProvider.connectionID "{id}" is invalid. Please make sure it refers to the ID of a CDbConnection application component.',
                    array('{id}'=>$id)));
        }
    }
    
    /**
    * kiem tra da ton tai connect toi social chua
    * 
    * @param mixed $identify
    * @return int
    */
    public function exists($identify=null)
    {
        if ($identify === null)
            $identify = $this->identify;
        $command = $this->getDbConnection()->createCommand();
        return $command->select('COUNT(*)')
            ->from($this->SocialProviderTableName)
            ->where('type = :type AND identify = :identify', array(':type'=>$this->type, ':identify'=>$identify))
            ->queryScalar();
    }
    
    /**
    * them connection toi social
    * 
    * @param int $userId
    * @param mixed $identify
    * @return int
    */
    public function add($userId=null, $identify=null)
    {
        if ($userId === null)
        {
            if (Yii::app()->user->isGuest === false)
                $userId = Yii::app()->user->id;
            else
                throw new CException(Yii::t('SocialProvider','SocialProvider.add "{id}" is invalid.', array('{id}'=>$userId)));
        }
        
        if ($identify === null)
            $identify = $this->identify;
        
        $command = $this->getDbConnection()->createCommand();
        return $command->insert($this->SocialProviderTableName, array(
            'user_id'=>$userId,
            'type'=>$this->type,
            'identify'=>$identify,
        ));
    }
    
    /**
    * remove connection to social
    * 
    * @param mixed $userId
    * @return int
    */
    public function remove($userId=null)
    {
        if ($userId === null)
        {
            if (Yii::app()->user->isGuest === false)
                $userId = Yii::app()->user->id;
            else
                throw new CException(Yii::t('SocialProvider','SocialProvider.add "{id}" is invalid.', array('{id}'=>$userId)));
        }
        
        $command = $this->getDbConnection()->createCommand();
        return $command->delete($this->SocialProviderTableName, 
            'user_id = :user_id AND type = :type',
            array(
                ':user_id'=>$userId,
                ':type'=>$this->type,
            )
        );
    }
    
    /**
    * get social connect profile
    * 
    * @param mixed $identify
    * @return array id, user_id, type, identify
    */
    public function getConnectProfile($identify=null)
    {
        if ($identify === null)
            $identify = $this->identify;
        
        $command = $this->getDbConnection()->createCommand();
        return $command->select('*')
            ->from($this->SocialProviderTableName)
            ->where('type = :type AND identify = :identify', array(':type'=>$this->type, ':identify'=>$identify))
            ->queryRow();
    }
    
    /**
    * xac thuc thong tin social
    * 
    */
    abstract public function authenticate();
    
    public function getData($url, $userId, $tokenResultParams)
    {
        $uriArray = parse_url($url);
        if (is_array($uriArray) && isset($uriArray['scheme'], $uriArray['host']))
        {
            $serverUri = $uriArray['scheme'].'://'.$uriArray['host'];
        }
        if ($serverUri != $this->server['server_uri'])
        {
            $this->server['server_uri'] = $serverUri;
            $this->getStore()->updateServer($this->server, $userId);
        }
        $request = new OAuthRequester($url, 'GET', $tokenResultParams);
        
        $result = $request->doRequest($userId, array(CURLOPT_SSL_VERIFYPEER => false));
        if ($result['code'] == 200)
        {
            Yii::trace(CVarDumper::dumpAsString($result), 'SocialProvider');
            return CJSON::decode($result['body']);
        }
        else
        {
            Yii::log(CVarDumper::dumpAsString($result), CLogger::LEVEL_ERROR, 'SocialProvider');
            return false;
        }
    }
    
    public function requestToken($consumerKey, $userId, $params=array())
    {
        $params = CMap::mergeArray(array(
            'oauth_callback' => Yii::app()->controller->createAbsoluteUrl('/'.Yii::app()->controller->route),
        ), $params);
        $params = CMap::mergeArray($params, $this->requestTokenParams);
        // Obtain a request token from the server
        $token = OAuthRequester::requestRequestToken($consumerKey, $userId, $params, 'POST', array(), array(CURLOPT_SSL_VERIFYPEER => false));

        // Callback to our (consumer) site, will be called when the user finished the authorization at the server
        $callback_uri = Yii::app()->controller->createAbsoluteUrl(Yii::app()->controller->route, array('consumer_key'=>$consumerKey, 'usr_id'=>$userId));

        // Now redirect to the autorization uri and get us authorized
        if (!empty($token['authorize_uri']))
        {
            // Redirect to the server, add a callback to our server
            if (strpos($token['authorize_uri'], '?'))
            {
                $uri = $token['authorize_uri'] . '&'; 
            }
            else
            {
                $uri = $token['authorize_uri'] . '?'; 
            }
            $uri .= 'oauth_token='.rawurlencode($token['token']).'&oauth_callback='.rawurlencode($callback_uri);
        }
        else
        {
            // No authorization uri, assume we are authorized, exchange request token for access token
           $uri = $callback_uri . '&oauth_token='.rawurlencode($token['token']);
        }

        Yii::app()->controller->redirect($uri);
    }
    
    public function requestAccessToken($consumerKey, $oauthToken, $userId, $options)
    {
        try
        {
            OAuthRequester::requestAccessToken($consumerKey, $oauthToken, $userId, 'POST', $options, array(CURLOPT_SSL_VERIFYPEER => false));
            return true;
        }
        catch (OAuthException2 $e)
        {
            // Something wrong with the oauth_token.
            // Could be:
            // 1. Was already ok, array(CURLOPT_SSL_VERIFYPEER => false)
            // 2. We were not authorized
            Yii::log($e->getMessage(), CLogger::LEVEL_ERROR, 'SocailConnect');
            return false;
        }
    }
    
    public function getConsumerKey($userId)
    {
        try
        {
            $this->server = $this->getStore()->getServer($this->server['consumer_key'], $userId);
            $consumerKey = $this->server['consumer_key'];
        }
        catch (OAuthException2 $e)
        {
            $consumerKey = $this->getStore()->updateServer($this->server, $userId);
        }
        return $consumerKey;
    }
    
    protected function getStore()
    {
        return Yii::app()->socials->getStore();
    }
}
